﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KnowledgeBaseIntermediary;
using SerializedData;

namespace KnowledgeBase
{
    /// <summary>
    /// The KnowledgeBase is responsible for providing the core with all information about states, commands, scenes and sensor
    /// that it needs for operation.
    /// </summary>
    public class KnowledgeBaseImpl:IKnowledgeBase
    {
        private DataCollection mDataCollection = DataCollection.Instance;

        public StateDTO getDTOByEvent(string UDPEvent)
        {
            SSensor sSensor = mDataCollection.getSensorPool().Find(o => ("" + o.getUdp()).Equals(UDPEvent));
            if (sSensor == null)
                throw new NotFoundException("No sensor is configured to handle this udp event");
            SState sState = mDataCollection.getStatePool().Find(o => (o.getId()).Equals(sSensor.getRefState()));
            if (sState == null)
                throw new NotFoundException("The configured sensor does not reference a state.");
            List<String> autoCommands= new List<String>();
            List<String> manualCommands= new List<String>();
            List<String> scenes= new List<String>();
            foreach(SCommand item in sState.getAutoCommands()) 
                autoCommands.Add(item.getName());
            foreach(SCommand item in sState.getManualCommands())
                manualCommands.Add(item.getName());
            foreach(SScene item in sState.getScenes())
                scenes.Add(item.getName());
            return new StateDTO(sState.getName(), new OutputObject(sState.getDescription(), sState.getTts()), sState.isChecked(), sState.getPriority(), autoCommands, scenes, manualCommands);
        }

        public StateDTO getDTOByCommand(string command)
        {
            

            SState sState = mDataCollection.getStatePool().Find(o => (o.getName()).Equals(command));
            if (sState == null)
                throw new NotFoundException("I can't find such a state.");
            List<String> autoCommands = new List<String>();
            List<String> manualCommands = new List<String>();
            List<String> scenes = new List<String>();
            foreach (SCommand item in sState.getAutoCommands())
                autoCommands.Add(item.getName());
            foreach (SCommand item in sState.getManualCommands())
                manualCommands.Add(item.getName());
            foreach (SScene item in sState.getScenes())
                scenes.Add(item.getName());
            return new StateDTO(sState.getName(),new OutputObject(sState.getDescription(),sState.getTts()), sState.isChecked(), sState.getPriority(), autoCommands, scenes, manualCommands);

        }

        public List<string> getSceneCommands(string currentState, string scene)
        {
            SState sState = mDataCollection.getStatePool().Find(o => ("" + o.getName()).Equals(currentState));
            if (sState == null)
                throw new NotFoundException("I can not find state " + currentState + " in knowledgebase");
            SScene sScene = sState.getScenes().Find(o => ("" + o.getName()).Equals(scene));
            if(sScene==null)
                throw new NotFoundException("I found state " + currentState + ", but it does not hold scene "+scene);

            List<String> commands = new List<string>();
            foreach (SCommand item in sScene.getCommands())
               commands.Add(item.getName());
            return commands;
        }

        public CommandObject getUDPByCommand(string currentState, string command)
        {
            SState sState = mDataCollection.getStatePool().Find(o => (""+o.getName()).Equals(currentState));
            if (sState == null)
                throw new NotFoundException("I can not find state "+currentState+" in knowledgebase");
            List<SCommand> autoCommands = sState.getAutoCommands();

            SCommand aCommand = autoCommands.Find(o => (o.getName()).Equals(command));
            List<SCommand> manualCommands = sState.getManualCommands();
            
            SCommand mCommand = manualCommands.Find(o => (o.getName()).Equals(command));
            if (aCommand == null)
            {
                aCommand = mCommand;
            }
            if (aCommand == null)
                throw new NotFoundException("I found state "+currentState+", but it does not reference command "+command+"");
            return (new CommandObject(new OutputObject(aCommand.getDescription(), aCommand.getTts()), aCommand.getUDP()));
        }


        public List<String> getAllAvailableStates()
        {
            List<SState> states = mDataCollection.getStatePool();
            List<String> ret = new List<String>();
            foreach (SState state in states)
                ret.Add(state.getName());
            return ret;
        }

    }
}
